﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using HeyoUi.Models.Data.Game;
using Newtonsoft.Json;

namespace HeyoUi.Util
{
    public class BmclGetter
    {
        private static ObservableCollection<NonLocalGameInfo> _versionList =
            new ObservableCollection<NonLocalGameInfo>();

        internal static async Task<IEnumerable<NonLocalGameInfo>> GetVersionList()
        {
            const string jsonUri = "http://bmclapi.bangbang93.com/mc/game/version_manifest.json";
            return await Task.Factory.StartNew(() =>
            {
                try
                {
                    using (WebClient client = new WebClient())
                    {
                        string jsonStr = client.DownloadString(new Uri(jsonUri));
                        McVersions versions = JsonConvert.DeserializeObject<McVersions>(jsonStr);
                        return new List<NonLocalGameInfo>(versions.Versions.Select(t =>
                            new NonLocalGameInfo { Version = t.Id, Uri = t.Url, Type = t.Type }));
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
#if DEBUG
                    throw;
#else
                    return null;
#endif
                }
            });
        }

        internal static async Task<IEnumerable<ForgeVersion>> GetForgeList(string version)
        {
            const string jsonUri = "https://bmclapi2.bangbang93.com/forge/minecraft/{0}";
            return await Task.Factory.StartNew(() =>
            {
                try
                {
                    using (WebClient client = new WebClient())
                    {
                        string jsonStr = client.DownloadString(new Uri(String.Format(jsonUri, version)));
                        DataTable table = JsonConvert.DeserializeObject<DataTable>(jsonStr);

                        //这是真的牛逼，那么长的linq表达式
                        IEnumerable<ForgeVersion> result = from DataRow item in table.Rows
                                     let files = (DataTable)item["files"]
                                     let forgeFile = (from DataRow file in files.Rows
                                                      select new ForgeFile(file["format"] as string, file["category"] as string,
                                                          file.Table.Columns.Contains("hash")?file["hash"] as string:null)).ToList()
                                     select new ForgeVersion(item["_id"] as string, item["version"] as string,
                                         (long)item["build"], item["mcversion"] as string, forgeFile);

                        return result;
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
#if DEBUG
                    throw;
#else
                    return null;
#endif
                }
            });
        }

        internal static async Task<IEnumerable<OptifineVersion>> GetOptifineList(string version)
        {
            const string jsonUri = "https://bmclapi2.bangbang93.com/optifine/{0}";
            return await Task.Factory.StartNew(() =>
            {
                try
                {
                    using (WebClient client = new WebClient())
                    {
                        string jsonStr = client.DownloadString(new Uri(String.Format(jsonUri, version)));
                        DataTable table = JsonConvert.DeserializeObject<DataTable>(jsonStr);

                        //这是真的牛逼，那么长的linq表达式
                        IEnumerable<OptifineVersion> result = from DataRow item in table.Rows
                            select new OptifineVersion(item["_id"] as string, item["mcversion"] as string,
                                item["patch"] as string, item["type"] as string, 0,
                                item["fileName"] as string);

                        return result;
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
#if DEBUG
                    throw;
#else
                    return null;
#endif
                }
            });
        }

        public static string GetLibDownloadUrl(string libFullName)
        {
            const bool bmcl = true;
            string[] splits = libFullName.Split(':');  //split it
            string ns = splits[0];                  //org.scala-lang
            string libName = splits[1];             //scala-library
            string version = splits[2];             //2.11.1
            if (bmcl)
            {
                const string bmclUrl = "https://bmclapi2.bangbang93.com/libraries/";
                return bmclUrl + $@"{ns.Replace(".", "/")}/{libName}/{version}/{libName}-{version}.jar";
            }
            else
            {
                return "http://files.minecraftforge.net/maven/" + $@"{ns.Replace(".", "/")}/{libName}/{version}/{libName}-{version}.jar";
            }
        }

        public static string GetClientDownloadUrl(string version)
        {
            return $@"https://bmclapi2.bangbang93.com/version/{version}/client";
        }

        public static string GetForgeDownloadUrl(long build)
        {
            return $"https://bmclapi2.bangbang93.com/forge/download/{build}";
        }

        public static string GetOptifineDownloadUrl(string mcVer, string type, string patch)
        {
            return $"https://bmclapi2.bangbang93.com/optifine/{mcVer}/{type}/{patch}";
        }

        private class Latest
        {
            [JsonProperty("snapshot")] public string Snapshot { get; set; }

            [JsonProperty("release")] public string Release { get; set; }
        }

        private class Versions
        {
            [JsonProperty("id")] public string Id { get; set; }

            [JsonProperty("type")] public string Type { get; set; }

            [JsonProperty("time")] public DateTime Time { get; set; }

            [JsonProperty("releaseTime")] public string ReleaseTime { get; set; }

            [JsonProperty("url")] public string Url { get; set; }
        }

        private class McVersions
        {
            [JsonProperty("latest")] public Latest Latest { get; set; }

            [JsonProperty("versions")] public List<Versions> Versions { get; set; }
        }

        public class ForgeVersion
        {
            public ForgeVersion(string id, string version, long build, string mcVersion, List<ForgeFile> files)
            {
                Id = id;
                Version = version;
                Build = build;
                McVersion = mcVersion;
                Files = files;
            }

            public string Id { get; set; }

            public string Version { get; set; }

            public long Build { get; set; }

            public string McVersion { get; set; }

            public List<ForgeFile> Files { get; set; }
        }

        public class ForgeFile
        {
            public ForgeFile(string format, string category, string hash)
            {
                Format = format;
                Category = category;
                Hash = hash;
            }

            public string Format { get; set; }

            public string Category { get; set; }

            public string Hash { get; set; }
        }

        public class OptifineVersion
        {
            public OptifineVersion(string id, string mcVersion, string patch, string type, int v, string fileName)
            {
                Id = id;
                McVersion = mcVersion;
                Patch = patch;
                Type = type;
                V = v;
                FileName = fileName;
            }

            public string Id { get; set; }
            public string McVersion { get; set; }
            public string Patch { get; set; }
            public string Type { get; set; }
            public int V { get; set; }
            public string FileName { get; set; }
        }
    }
}